package com.emaplink.cryptoutil.sm;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * @program: ztrust_pro_common
 * @description: 中文完整性判断
 * @author: 张桥
 * @create: 2025-10-29 17:04
 */
public class MessageTruncationHandler {

    /**
     * 清理字节数组，删除开头和结尾不完整的字符
     * @param bytes 原始字节数组
     * @return 只包含完整字符的字节数组
     */
    public static byte[] truncateToCompleteCharacters(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return new byte[0];
        }

        // 1. 找到第一个完整字符的起始位置
        int startIndex = findFirstCompleteChar(bytes, 0);
        if (startIndex == -1) {
            return new byte[0]; // 没有找到任何完整字符
        }

        // 2. 从起始位置开始，收集所有完整字符
        List<byte[]> completeChars = new ArrayList<>();
        int currentIndex = startIndex;

        while (currentIndex < bytes.length) {
            int charLength = getUtf8CharLength(bytes, currentIndex);

            // 检查是否有足够的字节构成完整字符
            if (charLength > 0 && currentIndex + charLength <= bytes.length) {
                // 提取完整字符的字节
                byte[] charBytes = new byte[charLength];
                System.arraycopy(bytes, currentIndex, charBytes, 0, charLength);
                completeChars.add(charBytes);
                currentIndex += charLength;
            } else {
                // 遇到不完整字符，停止收集
                break;
            }
        }

        // 3. 合并所有完整字符的字节
        return mergeByteArrays(completeChars);
    }

    /**
     * 从指定位置开始查找第一个完整字符的起始位置
     */
    private static int findFirstCompleteChar(byte[] bytes, int start) {
        for (int i = start; i < bytes.length; i++) {
            int charLength = getUtf8CharLength(bytes, i);
            if (charLength > 0 && i + charLength <= bytes.length) {
                return i; // 找到完整字符的起始位置
            }
        }
        return -1;
    }

    /**
     * 获取UTF-8字符的字节长度
     * @param bytes 字节数组
     * @param start 起始位置
     * @return 字符长度，如果起始位置不是有效的UTF-8字符开头则返回-1
     */
    private static int getUtf8CharLength(byte[] bytes, int start) {
        if (start >= bytes.length) {
            return -1;
        }

        byte firstByte = bytes[start];

        // ASCII字符 (0xxxxxxx)
        if ((firstByte & 0x80) == 0x00) {
            return 1;
        }
        // 2字节字符 (110xxxxx)
        else if ((firstByte & 0xE0) == 0xC0) {
            if (start + 1 < bytes.length && isContinuationByte(bytes[start + 1])) {
                return 2;
            }
        }
        // 3字节字符 (1110xxxx) - 中文字符通常在这里
        else if ((firstByte & 0xF0) == 0xE0) {
            if (start + 2 < bytes.length &&
                    isContinuationByte(bytes[start + 1]) &&
                    isContinuationByte(bytes[start + 2])) {
                return 3;
            }
        }
        // 4字节字符 (11110xxx)
        else if ((firstByte & 0xF8) == 0xF0) {
            if (start + 3 < bytes.length &&
                    isContinuationByte(bytes[start + 1]) &&
                    isContinuationByte(bytes[start + 2]) &&
                    isContinuationByte(bytes[start + 3])) {
                return 4;
            }
        }

        return -1; // 无效的UTF-8字符开头
    }

    /**
     * 检查是否为UTF-8连续字节 (10xxxxxx)
     */
    private static boolean isContinuationByte(byte b) {
        return (b & 0xC0) == 0x80;
    }

    /**
     * 合并多个字节数组
     */
    private static byte[] mergeByteArrays(List<byte[]> byteArrays) {
        if (byteArrays.isEmpty()) {
            return new byte[0];
        }

        // 计算总长度
        int totalLength = 0;
        for (byte[] array : byteArrays) {
            totalLength += array.length;
        }

        // 合并数组
        byte[] result = new byte[totalLength];
        int currentIndex = 0;
        for (byte[] array : byteArrays) {
            System.arraycopy(array, 0, result, currentIndex, array.length);
            currentIndex += array.length;
        }

        return result;
    }

    /**
     * 安全地将字节数组转换为字符串，确保只包含完整字符
     */
    public static String bytesToSafeString(byte[] bytes) {
        byte[] completeBytes = truncateToCompleteCharacters(bytes);
        return new String(completeBytes, StandardCharsets.UTF_8);
    }

    /**
     * 测试截取功能
     */
    public static void testTruncation(String original, int start, int end) {
        System.out.println("\n=== 测试截取 ===");
        System.out.println("原始文本: " + original);

        byte[] originalBytes = original.getBytes(StandardCharsets.UTF_8);
        System.out.println("原始字节长度: " + originalBytes.length);

        // 模拟截取
        byte[] truncated = new byte[end - start];
        System.arraycopy(originalBytes, start, truncated, 0, end - start);
        System.out.println("截取范围: [" + start + ", " + end + ")");
        System.out.println("截取后字节长度: " + truncated.length);

        // 清理不完整数据
        byte[] cleaned = truncateToCompleteCharacters(truncated);
        System.out.println("清理后字节长度: " + cleaned.length);

        String result = new String(cleaned, StandardCharsets.UTF_8);
        System.out.println("清理后文本: " + result);
        System.out.println("文本长度: " + result.length());
    }

    public static void main(String[] args) {
        // 测试用例
        String testMessage = "Hello你好World世界Java编程";

        System.out.println("原始报文: " + testMessage);
        byte[] originalBytes = testMessage.getBytes(StandardCharsets.UTF_8);
        System.out.println("原始字节数组长度: " + originalBytes.length);

        // 测试各种截取情况
        testTruncation(testMessage, 0, 10);  // 包含完整字符
        testTruncation(testMessage, 5, 15);  // 可能截断中文字符
        testTruncation(testMessage, 7, 12);  // 在中文字符中间截断
        testTruncation(testMessage, 10, 20); // 包含英文和中文

        // 测试边缘情况
        System.out.println("\n=== 边缘情况测试 ===");

        // 空数组
        byte[] empty = new byte[0];
        System.out.println("空数组清理后长度: " + truncateToCompleteCharacters(empty).length);

        // 只有不完整数据的数组
        byte[] incomplete = new byte[] {(byte)0xE4, (byte)0xB8}; // "你"的前两个字节
        System.out.println("不完整数据清理后长度: " + truncateToCompleteCharacters(incomplete).length);

        // 随机字节数组
        byte[] random = new byte[] {0x48, 0x65, (byte)0xE4, (byte)0xB8}; // "He" + "你"的前两个字节
        String randomResult = bytesToSafeString(random);
        System.out.println("随机数据清理后: " + randomResult);
    }
}
